﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FPPrinter.utiles;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Common;
using SharpCompress.Readers;

namespace FPPrinter.Models.SourceFiles
{
    public class SourceFileManager : ISourceFileManager, IDisposable
    {
        private string _rootfolder = "tem/";

        public void Deconstruct()
        {
        }

        void AddFiles(params string[] files)
        {
            var fadd = files.Where(x => !_files.Exists(b => b.Url == x));

            foreach (var f in fadd)
            {
                _files.Add(new SourceFile(f, _rootfolder));
                RootLatest = Path.GetDirectoryName(f);
            }


            RaiseFilesChanged();
        }


        public IEnumerable<string> GetPdfFiles(IEnumerable<string> files)
        {
            List<string> pdfFiles = new List<string>();


            foreach (string file in files)
            {
                if (Directory.Exists(file))
                {
                    // If the dropped item is a directory, get all pdf files from it
                    pdfFiles.AddRange(Directory.GetFiles(file, "*.pdf", SearchOption.AllDirectories));
                }
                else if (File.Exists(file) &&
                         Path.GetExtension(file)
                             .Equals(".pdf", StringComparison.OrdinalIgnoreCase)) // if its is file names
                {
                    // If it's a file and it's a PDF, add it
                    pdfFiles.Add(file);
                }

                else if (File.Exists(file) &&
                         Path.GetExtension(file).Equals(".zip", StringComparison.OrdinalIgnoreCase)
                        ) // if its is file names
                {
                    // If it's a file and it's a PDF, add it
                    pdfFiles.AddRange(  GetPdfFileByZip(file)); ;
                }

                else if (File.Exists(file) &&
                         Path.GetExtension(file).Equals(".rar", StringComparison.OrdinalIgnoreCase)
                        ) // if its is file names
                {
                    // If it's a file and it's a PDF, add it
                    pdfFiles.AddRange(GetPdfFileByRar(file));
                }
            }

            return pdfFiles;
        }
        
        
        Random _random = new Random();

        private IEnumerable<string> GetPdfFileByZip(string file)
        {
            string zipFilePath =file;
            string outputFolder = $@"{_rootfolder}unZiped_{_random.Next(9000):0000}/";

            // Decompress the ZIP file to the specified folder
            ZipFile.ExtractToDirectory(zipFilePath, outputFolder);
            
            // Return the path to the output folder
            // Console.WriteLine(outputFolder);
            
            var pdfs= Directory.GetFiles(outputFolder, "*.pdf", SearchOption.AllDirectories);
            return pdfs;
        }     
        private IEnumerable<string> GetPdfFileByRar(string file)
        {
  
            // string rarFilePath = @"C:\path\to\rarfile.rar";
            // string outputFolder = @"C:\path\to\outputfolder";
            string rarFilePath =file;
            string outputFolder = $@"{_rootfolder}unZiped_{_random.Next(9000):0000}/";

            
            // Open the RAR file
            using (var stream = File.OpenRead(rarFilePath))
            {
                // Create a RarReader instance
                using (var reader = ReaderFactory.Open(stream))
                {
                    // Iterate over the entries in the RAR file
                    while (reader.MoveToNextEntry())
                    {
                        if (!reader.Entry.IsDirectory)
                        {
                            // Extract the entry to the specified folder
                            outputFolder.MakeSurePathIsAvaliable();
                            reader.WriteEntryToDirectory(outputFolder, new ExtractionOptions() { ExtractFullPath = true });
                        }
                    }
                }
            }
           
            var pdfs= Directory.GetFiles(outputFolder, "*.pdf", SearchOption.AllDirectories);
            return pdfs;
            
        }

        public (int S, int L, int T) Analysis(params string[] files2)
        {

            var fs = GetPdfFiles(files2.ToList()).ToArray();
            AddFiles(fs);

            // Task.WhenAll(   _files.Select( f=> Task.Run(()=> f => f.Analysis() )) );
            Task.WaitAll(_files.Select(f => Task.Run((Action)(() => f.Analysis()))).ToArray());
            var ss = _files.Count(x => x.FileType == FileType.Short);
            var ls = _files.Count(x => x.FileType == FileType.Long);


            RaiseFilesChanged();

            return (ss, ls, _files.Count());
        }

        List<ISourceFile> _files = new List<ISourceFile>();
        public IEnumerable<ISourceFile> Files => _files;
        public string RootLatest { get; private set; } = "";
        event EventHandler<IEnumerable<ISourceFile>> _FilesChanged;

        public event EventHandler<IEnumerable<ISourceFile>> FilesChanged
        {
            add
            {
                _FilesChanged += value;
                RaiseFilesChanged();
            }
            remove { _FilesChanged -= value; }
        }

        void RaiseFilesChanged()
        {
            _FilesChanged?.Invoke(this, _files);
        }

        public void Clear()
        {
            _files.Clear();
            RaiseFilesChanged();
        }

        public void Remove(string url)
        {
            _files.RemoveAll(x => x.Url == url);
            RaiseFilesChanged();
        }

        public void Dispose()
        {
            try
            {
                _files = null;
                GC.Collect();

                Directory.Delete(_rootfolder, true);
                Console.WriteLine($"{_rootfolder} deconstructed");
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
    }
}